
#include <jem/base/limits.h>
#include <jem/base/Error.h>
#include <jem/base/PrecheckException.h>
#include <jem/util/Properties.h>
#include "utilities.h"
#include "Names.h"
#include "Material.h"


//=======================================================================
//   class Material
//=======================================================================

//-----------------------------------------------------------------------
//   destructor
//-----------------------------------------------------------------------


Material::~Material ()
{}


//-----------------------------------------------------------------------
//   configure
//-----------------------------------------------------------------------


void Material::configure ( const Properties& props )
{}


//-----------------------------------------------------------------------
//   getConfig
//-----------------------------------------------------------------------


void Material::getConfig ( const Properties& conf ) const
{}


//=======================================================================
//   class IsoMaterial
//=======================================================================

//-----------------------------------------------------------------------
//   constructors & destructor
//-----------------------------------------------------------------------


IsoMaterial::IsoMaterial ( int rank )
{
  JEM_PRECHECK ( rank >= 1 && rank <= 3 );

  rank_    = rank;
  young_   = 1.0;
  poisson_ = 1.0;
}


IsoMaterial::~IsoMaterial ()
{}


//-----------------------------------------------------------------------
//   configure
//-----------------------------------------------------------------------


void IsoMaterial::configure ( const Properties& props )
{
  using jem::maxOf;

  props.find ( young_,   PropNames::YOUNG_MODULUS,
               0.0,      maxOf( young_ ) );
  props.find ( poisson_, PropNames::POISSON_RATIO,
               0.0,      0.5 );
}


//-----------------------------------------------------------------------
//   getConfig
//-----------------------------------------------------------------------


void IsoMaterial::getConfig ( const Properties& conf ) const
{
  conf.set ( PropNames::YOUNG_MODULUS, young_   );
  conf.set ( PropNames::POISSON_RATIO, poisson_ );
}


//-----------------------------------------------------------------------
//   getStiffMat
//-----------------------------------------------------------------------


Matrix IsoMaterial::getStiffMat () const
{
  const int     n  = STRAIN_COUNTS[rank_];

  const double  e  = young_;
  const double  nu = poisson_;

  Matrix        s ( n, n );


  s = 0.0;

  if      ( rank_ == 1 )
  {
    s(0,0) = e;
  }
  else if ( rank_ == 2 )
  {
    const double  a = e / (1.0 - nu * nu);

    s(0,0) = a;
    s(0,1) = a * nu;
    s(1,1) = a;
    s(2,2) = a * 0.5 * (1.0 - nu);
  }
  else if ( rank_ == 3 )
  {
    const double  a = e / ((1.0 + nu) * (1.0 - 2.0 * nu));
    const double  b = 0.5 * (1.0 - 2.0 * nu);
    const double  c = 1.0 - nu;

    s(0,0) = a * c;
    s(0,1) = s(0,2) = a * nu;
    s(1,1) = s(0,0);
    s(1,2) = s(0,1);
    s(2,2) = s(0,0);
    s(3,3) = a * b;
    s(4,4) = s(3,3);
    s(5,5) = s(3,3);
  }
  else
  {
    throw jem::Error (
      JEM_FUNC,
      "unexpected rank: " + String ( rank_ )
    );
  }

  // Copy lower triangle of the stress-strain matrix.

  for ( int i = 0; i < n; i++ )
  {
    for ( int j = 0; j < i; j++ )
    {
      s(i,j) = s(j,i);
    }
  }

  return s;
}
